package com.info.zhiduoduo.core.service.impl;

import com.baomidou.mybatisplus.mapper.Condition;
import com.info.zhiduoduo.common.configs.CommonConfig;
import com.info.zhiduoduo.common.configs.KltPayConfig;
import com.info.zhiduoduo.common.configs.PayConfig;
import com.info.zhiduoduo.common.configs.WhetherTestConfig;
import com.info.zhiduoduo.common.configs.ZddUrlConfig;
import com.info.zhiduoduo.common.constants.Constants;
import com.info.zhiduoduo.common.constants.SmartResult;
import com.info.zhiduoduo.common.constants.StatusMsg;
import com.info.zhiduoduo.common.constants.company.CompanyPayType;
import com.info.zhiduoduo.common.constants.partner.PartnerBrokerageState;
import com.info.zhiduoduo.common.constants.partner.PartnerCrowdsourceCostState;
import com.info.zhiduoduo.common.constants.partner.PartnerStudioWithdrawState;
import com.info.zhiduoduo.common.constants.partner.RemitType;
import com.info.zhiduoduo.common.constants.pay.PayTypeSn;
import com.info.zhiduoduo.common.constants.project.CalcAmountType;
import com.info.zhiduoduo.common.constants.project.CompanyProjectState;
import com.info.zhiduoduo.common.constants.project.ProjectType;
import com.info.zhiduoduo.common.exception.Asserts;
import com.info.zhiduoduo.common.exception.RollbackException;
import com.info.zhiduoduo.common.exception.SmartException;
import com.info.zhiduoduo.common.utils.DateUtil;
import com.info.zhiduoduo.common.utils.LogUtil;
import com.info.zhiduoduo.common.utils.MD5Util;
import com.info.zhiduoduo.common.utils.NumberUtil;
import com.info.zhiduoduo.common.utils.StringUtil;
import com.info.zhiduoduo.core.configs.Redis.RedisKey;
import com.info.zhiduoduo.core.dto.dingdingnotice.GroupCode;
import com.info.zhiduoduo.core.formbean.CalcProjectChargesFormBean;
import com.info.zhiduoduo.core.formbean.CheckLongTermSubProjectFormBean;
import com.info.zhiduoduo.core.formbean.ProjectCheckFormBean;
import com.info.zhiduoduo.core.service.CommonService;
import com.info.zhiduoduo.core.service.CoreBrokerageService;
import com.info.zhiduoduo.core.service.CoreCompanyService;
import com.info.zhiduoduo.core.service.CoreLongTermProjectService;
import com.info.zhiduoduo.core.service.CoreProjectService;
import com.info.zhiduoduo.core.service.DingdingNoticeService;
import com.info.zhiduoduo.core.service.WxCrowdsourceMessageService;
import com.info.zhiduoduo.core.service.WxMessageService;
import com.info.zhiduoduo.core.service.WxPartnerMessageService;
import com.info.zhiduoduo.core.service.ZhiduoduoProjectService;
import com.info.zhiduoduo.core.service.common.BaseService;
import com.info.zhiduoduo.core.service.common.RedisService;
import com.info.zhiduoduo.core.service.payment.project.ProjectJiugeOfflinePaymentServiceImpl;
import com.info.zhiduoduo.core.service.payment.project.ProjectJiugeUnifyPaymentServiceImpl;
import com.info.zhiduoduo.core.service.payment.project.ProjectOfflinePaymentServiceImpl;
import com.info.zhiduoduo.core.service.payment.project.ProjectPaymentService;
import com.info.zhiduoduo.repository.dto.maker.MakerDetailDto;
import com.info.zhiduoduo.repository.dto.maker.StudioDetailDto;
import com.info.zhiduoduo.repository.dto.project.CalcProjectChargesDto;
import com.info.zhiduoduo.repository.dto.project.ProjectDto;
import com.info.zhiduoduo.repository.dto.project.ProjectServiceChargeDto;
import com.info.zhiduoduo.repository.dto.project.ProjectTaxFeeDto;
import com.info.zhiduoduo.repository.entity.company.*;
import com.info.zhiduoduo.repository.entity.invoice.Invoice;
import com.info.zhiduoduo.repository.entity.maker.Maker;
import com.info.zhiduoduo.repository.entity.maker.MakerAccountflow;
import com.info.zhiduoduo.repository.entity.maker.MakerStudio;
import com.info.zhiduoduo.repository.entity.order.TradeRecord;
import com.info.zhiduoduo.repository.entity.partner.PartnerBrokerage;
import com.info.zhiduoduo.repository.entity.partner.PartnerMonthlyCrowdCost;
import com.info.zhiduoduo.repository.entity.partner.PartnerStudioWithdraw;
import com.info.zhiduoduo.repository.entity.system.SystemCfg;
import com.info.zhiduoduo.repository.entity.system.SystemProjectcategory;
import com.info.zhiduoduo.repository.mapper.company.CompanyPaymentMapper;
import com.info.zhiduoduo.repository.mapper.company.CompanyProjectMapper;
import com.info.zhiduoduo.repository.mapper.crowdsource.CrowdsourceAccountMapper;
import com.info.zhiduoduo.repository.mapper.crowdsource.CrowdsourceProjectItemMapper;
import com.info.zhiduoduo.repository.mapper.crowdsource.CrowdsourceProjectMapper;
import com.info.zhiduoduo.repository.mapper.invoice.InvoiceMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerStudioMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerBrokerageMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerCompanyMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerSubMapper;
import com.info.zhiduoduo.repository.mapper.system.ProjectCategoryMapper;
import com.info.zhiduoduo.repository.mapper.taxer.TaxerInvoiceMapper;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import lombok.extern.slf4j.Slf4j;

@Transactional
@Slf4j
@Service
public class ZhiduoduoProjectServiceImpl extends BaseService implements ZhiduoduoProjectService {

	@Autowired
	MakerMapper makerMapper;
	@Autowired
	PartnerCompanyMapper partnerCompanyMapper;
	@Autowired
	CompanyPaymentMapper companyPaymentMapper;
	@Autowired
	PartnerBrokerageMapper partnerBrokerageMapper;
	@Autowired
	ProjectCategoryMapper projectCategoryMapper;
	@Autowired
	CompanyProjectMapper projectMapper;
	@Autowired
	CrowdsourceAccountMapper crowdsourceAccountMapper;
	@Autowired
	CrowdsourceProjectItemMapper crowdsourceProjectItemMapper;
	@Autowired
	CrowdsourceProjectMapper crowdsourceProjectMapper;
	@Autowired
	MakerStudioMapper makerStudioMapper;
	@Autowired
	TaxerInvoiceMapper taxerInvoiceMapper;
	@Autowired
	InvoiceMapper invoiceMapper;
	@Autowired
	PartnerSubMapper partnerSubMapper;
	@Autowired
	PartnerMapper partnerMapper;

	@Autowired
	CoreCompanyService coreCompanyService;
	@Autowired
	DingdingNoticeService dingdingNoticeService;
	@Autowired
	WxMessageService wxMessageService;
	@Autowired
	WxPartnerMessageService wxPartnerMessageService;
	@Autowired
	WxCrowdsourceMessageService wxCrowdsourceMessageService;
	@Autowired
	CeoNoticeService ceoNoticeService;
	@Autowired
	CoreProjectService coreProjectService;
	@Autowired
	ProjectJiugeUnifyPaymentServiceImpl jiugeUnifyPaymentService;
	@Autowired
	ProjectOfflinePaymentServiceImpl offlinePaymentService;
	@Autowired
	ProjectJiugeOfflinePaymentServiceImpl jiugeOfflinePaymentService;
	@Autowired
	CoreBrokerageService coreBrokerageService;
	@Autowired
	CommonService commonService;
	@Autowired
	CoreLongTermProjectService coreLongTermProjectService;

	@Autowired
	CommonConfig commonConfig;
	@Autowired
	ZddUrlConfig zddUrlConfig;
	@Autowired
	PayConfig payConfig;
	@Autowired
	KltPayConfig kltPayConfig;
	@Autowired
	WhetherTestConfig whetherTestConfig;
	@Autowired
	RedisService redisService;

	@Override
	public void checkProjectAmountBeforePublish(CompanyProject project) {
		int userid = project.getUserid();
		MakerDetailDto userDetail = makerMapper.getUserDetail(userid);
		Asserts.notNull(userDetail, StatusMsg.StatusMsg_201);
		//判断创客是否开户
		Asserts.isTrue(makerStudioMapper.isStudioOpen(userid), StatusMsg.StatusMsg_204);
		Asserts.isTrue(NumberUtil.equals(userDetail.getState(), Constants.user_state_2), StatusMsg.StatusMsg_231);

		// 天津创客还未开税户的,不能交易
		if (NumberUtil.intIn(userDetail.getOpeningLocation(), 1,3) && !NumberUtil.equals(userDetail.getTaxAcctState(), 3)) {
			throw SmartException.of(StatusMsg.StatusMsg_260);
		}
		// 创客申请注销已受理的，不能发布项目
		if (NumberUtil.equals(userDetail.getRescissionState(), Constants.user_rescission_state_2)) {
			throw SmartException.of(StatusMsg.StatusMsg_261);
		}

		//是否超过限额
		BigDecimal projectamount = project.getProjectamount();
		coreProjectService.checkMakerQuota(project.getCompid(), userid, project.getProjectid(), project.getType(), projectamount,CalcAmountType.PROCESSING);

		//计算服务费和税费
		CalcProjectChargesFormBean formBean = new CalcProjectChargesFormBean(CalcAmountType.CHECKED, userid, project.getCompid(), 0, 0,
				project.getType(), project.getInvoicetype(), projectamount);
		CalcProjectChargesDto calcProjectChargesDto = coreProjectService.calcProjectCharge(formBean);
		//计算失败，直接报错
		if (calcProjectChargesDto == null || calcProjectChargesDto.getServiceCharge() == null ||
				calcProjectChargesDto.getTaxFee() == null) {
			throw SmartException.of(StatusMsg.StatusMsg_199);
		}

		//更新项目的服务费率和合伙人的项目服务费率
		project.setProjectservicecharge(calcProjectChargesDto.getServiceCharge())
				.setProjectBaseServiceRate(calcProjectChargesDto.getBaseServiceRatio())
				.setProjectPartnerServiceRate(calcProjectChargesDto.getPartnerProjectServiceRatio())
				.updateById();
		BigDecimal totalCharges = calcProjectChargesDto.getServiceCharge().add(calcProjectChargesDto.getTaxFee());
		LogUtil.info("需要的服务费：" + totalCharges.toString());
		if (projectamount.compareTo(totalCharges) < 0) {
			throw SmartException.of(StatusMsg.StatusMsg_311).setData(totalCharges);
		}
	}

	@Override
	public void doAfterProjectCreated(CompanyProject project) {
		// 判断是否是合伙人提现项目，将合伙人提现申请记录的状态修改为已处理
		List<Integer> wdids = StringUtil.splitToInt(project.getPartnerWithdrawId(), ",");
		if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(wdids)) {
			for (Integer wdid : wdids) {
				new PartnerStudioWithdraw().setId(wdid)
						.setStarttime(new Date())
						.setProjectid(project.getProjectid())
						.setState(PartnerStudioWithdrawState.HANDLED)
						.updateById();
			}
		}
	}

	@Override
	public void doAfterProjectDeletedOrCancelled(CompanyProject project) {
		// 判断是否是合伙人提现发布的项目,是的话, 需要修改状态
		List<Integer> wdids = StringUtil.splitToInt(project.getPartnerWithdrawId(), ",");
		if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(wdids)) {
			for (Integer wdid : wdids) {
				new PartnerStudioWithdraw().setId(wdid)
						.setProjectid(0)
						.setState(PartnerStudioWithdrawState.APPLIED)
						.updateById();
			}
		}
	}

	@Override
	public SmartResult publishProject(CompanyProject project) {
		if (project == null) return SmartResult.fail(StatusMsg.StatusMsg_301);

		int compid = project.getCompid();
		CompanyPayment companyPayment = companyPaymentMapper.getCompanyPayment(compid,project.getPayId());
		if (companyPayment == null) return SmartResult.fail(StatusMsg.StatusMsg_330);

		// 分布式锁，不能重复发布同一项目
		String key = RedisKey.genZDDProjectPublishingLockKey(project.getProjectid());
		boolean lock = redisService.getLock(key, UUID.randomUUID().toString(), 60);
		if (!lock) return SmartResult.fail(StatusMsg.StatusMsg_366);

		try {
			// 修改项目开始时间/状态
			boolean started = project.setProjectstart(new Date()).setState(CompanyProjectState.PROCESSING).updateById();
			if (!started) return SmartResult.fail();

			coreBrokerageService.prepareProjectBrokerage(compid, project.getUserid(), project.getProjectid(), ProjectType.ZHIDUODUO);

			ProjectPaymentService projectPaymentService = getProjectPaymentService(project);
			if (projectPaymentService != null) {
				// 发布完成前, 处理账户余额扣款
				projectPaymentService.deductCompanyBalanceForPublishProject(companyPayment, project);
			} else {
				throw SmartException.of(StatusMsg.StatusMsg_454);
			}

			return finishPublishOrCheckProject(project);
		} finally {
			// 释放分布式锁
			redisService.releaseLock(key);
		}
	}

	/**
	 * 发布完成或者继续验收项目
	 */
	private SmartResult finishPublishOrCheckProject(CompanyProject project) {
		try {
			//企业收藏创客
			new CompanyUser().setCompid(project.getCompid()).setUserid(project.getUserid()).insert();
		} catch (Exception ignored) {}

		//如果是自动验收，直接验收
		Integer autoCheck = project.getAutoCheck();
		if (autoCheck != null && autoCheck == 1) {
			//设置项目的状态
			project.setProjectcheckstart(new Date()).setProjectcheckend(new Date()).setState(CompanyProjectState.CHECKING).updateById();

			//验收项目,并支付
			SmartResult paySmartResult = handleProjectCheckedAndPay(project);
			LogUtil.info("调用支付,返回结果: " + paySmartResult.toString());

			//支付失败,返回提示
			if (paySmartResult.isFailed()) return paySmartResult;
			doAfterCheckSuccess(project, false);
			return paySmartResult;
		} else {
			//通知创客，然后返回
			wxMessageService.notifyUserProjectPublish(project.getProjectid());
			return SmartResult.success();
		}
	}

	public SmartResult checkProject(ProjectCheckFormBean formBean) throws RollbackException {
		Asserts.notNull(formBean);
		int projectid = formBean.getProjectid();
		CompanyProject project = new CompanyProject().selectById(projectid);
		Asserts.notNull(project, StatusMsg.StatusMsg_301);
		Asserts.isTrue(project.getState() == CompanyProjectState.CHECKING, StatusMsg.StatusMsg_303);

		int state = formBean.getState();
		if (state == CompanyProjectState.CHECKED) {

			//验收项目,并支付
			SmartResult paySmartResult = handleProjectCheckedAndPay(project);
			LogUtil.info("调用支付,返回结果: " + paySmartResult.toString());

			//支付失败,返回提示
			if (paySmartResult.isFailed()) return paySmartResult;
			doAfterCheckSuccess(project, true);
			return paySmartResult;
		} else if (state == CompanyProjectState.CHECK_REFUSED) {
			//拒绝验收,将项目置为 仲裁中.
			project.setArbitrate(Constants.arbitratetstate_2)
					.setRejectReason(formBean.getRejectReason())
					.setState(CompanyProjectState.CHECK_REFUSED)
					.setProjectcheckend(new Date())
					.updateById();
			//通知创客
			wxMessageService.notifyUserProjectRefused(projectid);
		}

		return smartResult();
	}

	@Override
	public SmartResult checkLongTermProject(CheckLongTermSubProjectFormBean formBean) {
		String phone = formBean.getPhone();
		String verifyCode = formBean.getVerifyCode();
		String payPassword = formBean.getPayPassword();
		// 校验验证码
		commonService.checkPhoneVerifyCode(phone, verifyCode);

		Asserts.notNull(formBean);
		int projectid = formBean.getProjectid();
		BigDecimal dealamount = formBean.getDealamount();
		CompanyProject project = new CompanyProject().selectById(projectid);
		Asserts.notNull(project, StatusMsg.StatusMsg_301);
		Asserts.isTrue(project.getState() == CompanyProjectState.CHECKING, StatusMsg.StatusMsg_303);
		LongTermProject longTermProject = new LongTermProject().selectById(project.getParentProjectid());
		Asserts.notNull(longTermProject, StatusMsg.StatusMsg_347);

		CompanyPayment companyPayment = companyPaymentMapper.getCompanyPayment(project.getCompid(),project.getPayId());
		Asserts.notNull(project, StatusMsg.StatusMsg_330);

		//校验创客状态
		Integer userid = longTermProject.getUserid();
		MakerDetailDto userDetail = makerMapper.getUserState(userid);
		if (!NumberUtil.equals(userDetail.getState(), Constants.user_state_2)) {
			return smartResult(StatusMsg.StatusMsg_231);
		}
		// 天津/芜湖创客还未开税户的,不能交易
		if (NumberUtil.intIn(userDetail.getOpeningLocation(), 1,3) && !NumberUtil.equals(userDetail.getTaxAcctState(), 3)) {
			return smartResult(StatusMsg.StatusMsg_260);
		}
		// 创客申请注销已受理的，不能发布项目
		if (NumberUtil.equals(userDetail.getRescissionState(), Constants.user_rescission_state_2)) {
			return smartResult(StatusMsg.StatusMsg_261);
		}
		// 增加如果企业支付方式是支付宝 判断创客是否填写支付宝账号
		if (PayTypeSn.ZFB.equals(companyPayment.getPayTypeSn()) && StringUtil.isEmpty(userDetail.getAlipayAccount())) {
			return smartResult(StatusMsg.StatusMsg_485);
		}

		int compid = project.getCompid();
		// 校验支付密码
		coreCompanyService.checkCompanyPayPassword(project.getCompid(), payPassword);
		// 检查长期项目总金额是否超过
		coreLongTermProjectService.checkTotalAmount(longTermProject, dealamount);
		// 验证企业余额是否足够
		SmartResult checkAccountResult = coreProjectService.checkCompanyAccountForProject(compid,project.getPayId(), dealamount);
		if (checkAccountResult.isFailed()) return checkAccountResult;
		// 是否超过限额
		coreProjectService.checkMakerQuota(compid, project.getUserid(), projectid, project.getType(), dealamount, CalcAmountType.CHECKED);

		SmartResult smartResult;
		int state = formBean.getState();
		if (state == CompanyProjectState.CHECKED) {

			// 当金额大于0时,才去支付,等于0,项目直接完成
			if (dealamount.doubleValue() == 0) {
				project.setProjectdealamount(dealamount)
						.setProjectcheckend(new Date())
						.setState(CompanyProjectState.COMPLETED)
						.setProjectcheckend(new Date())
						.setProjectfinish(new Date())
						.updateById();
				smartResult = SmartResult.success();
			} else {
				//验收项目
				boolean update = project.setProjectdealamount(dealamount)
						.setProjectcheckend(new Date())
						.setState(CompanyProjectState.CHECKED)
						.updateById();
				Asserts.isTrue(update, StatusMsg.StatusMsg_199);
				// 更新长期项目已验收的总金额.
				longTermProject.setPaidAmount(longTermProject.getPaidAmount().add(dealamount)).updateById();
				// 企业余额扣款
				ProjectPaymentService projectPaymentService = getProjectPaymentService(project);
				if (projectPaymentService != null) {
					// 发布完成前, 处理账户余额扣款
					projectPaymentService.deductCompanyBalanceForPublishProject(companyPayment, project);
				} else {
					throw SmartException.of(StatusMsg.StatusMsg_454);
				}
				// 支付
				smartResult = handleProjectPayment(project);
				LogUtil.info("调用支付,返回结果: " + smartResult.toString());
				//支付失败,返回提示
				if (smartResult.isFailed()) return smartResult;
			}
			doAfterCheckSuccess(project, true);
			return smartResult;
		} else if (state == CompanyProjectState.CHECK_REFUSED) {
			//拒绝验收
			project.setRejectReason(formBean.getRejectReason())
					.setState(CompanyProjectState.CHECK_REFUSED)
					.setProjectcheckend(new Date())
					.updateById();
			//通知创客
			wxMessageService.notifyUserProjectRefused(projectid);
		}
		return SmartResult.fail(StatusMsg.StatusMsg_199);
	}

	private void doAfterCheckSuccess(CompanyProject project, boolean notifyMaker) {
		int projectid = project.getProjectid();
		try {
			//通知创客
			if (notifyMaker) wxMessageService.notifyUserProjectPassed(projectid);
			//查询创客
			Maker maker = new Maker().selectById(project.getUserid());
			//判断创客类型，根据不同的类型往不同的公众号发送公告
			if (null != maker) {
				wxMessageService.notifyMakerEvaluate(projectid);
			} else {
				LogUtil.error("企业验收项目发送评价通知-创客不存在");
			}
		} catch (Exception e) {
			log.error(" 企业验收项目-发送微信通知异常！", e);
		}
	}

	/**
	 * 处理项目验收完成,设置成交价,更新状态,并支付。
	 * <p>此流程之后,如果数据库操作失败,则会抛出异常,数据回滚.
	 * <p>如果是发起了支付,但是支付失败,则可以发起重新支付.
	 */
	@Override
	public SmartResult handleProjectCheckedAndPay(CompanyProject project) {
		if (project == null) return errorParamSmartResult();

		//验收项目时，判断当前项目是否是12 验证中的项目，不是则返回抱错。
		//将项目状态设置为已验收。设置成交价
		//验收完成，调用后台项目接口，处理项目并支付
		boolean update = project.setProjectdealamount(project.getProjectamount())
				.setProjectcheckend(new Date())
				.setState(CompanyProjectState.CHECKED)
				.updateById();

		if (update) return handleProjectPayment(project);

		throw SmartException.of(StatusMsg.StatusMsg_303);
	}

	/**
	 * 处理项目款的支付， 代付给创客或仲裁返款给企业。
	 */
	public SmartResult handleProjectPayment(CompanyProject project) {

		if (project == null) return smartResult(StatusMsg.StatusMsg_301);

		LogUtil.info("处理项目款支付: project = " + project.toString());
		if (project.getState() != CompanyProjectState.CHECKED) {
			return smartResult(StatusMsg.StatusMsg_303);
		}

		Integer projectid = project.getProjectid();
		int projectType = NumberUtil.safeInt(project.getType());
		Integer userid = project.getUserid();

		// 分布式锁，不能重复支付同一项目
		String key = RedisKey.genZDDProjectPayingLockKey(project.getProjectid());
		boolean lock = redisService.getLock(key, UUID.randomUUID().toString(), 60);
		if (!lock) return SmartResult.fail(StatusMsg.StatusMsg_366);

		try {
			//项目金额
			BigDecimal dealAmount = project.getProjectdealamount();

			//代付给创客
			StudioDetailDto makerStudio = makerStudioMapper.getStudioDetail(userid);
			if (makerStudio == null) return smartResult(StatusMsg.StatusMsg_201);
			//2023年2月22日  业务费率优化需求  发单接口判断企业费率是否开启，开启的话使用企业费率
			CompanyTax companyTax = new CompanyTax().selectById(project.getCompid());
			if (companyTax != null && NumberUtil.equals(companyTax.getCompanyTaxFlag(), Constants.TRUE)) {
				makerStudio.setGenLowServiceRate(companyTax.getGenLowServiceRate());
				makerStudio.setGenHighServiceRate(companyTax.getGenHighServiceRate());
				makerStudio.setGenHighTaxRate(companyTax.getGenHighTaxRate());
				makerStudio.setSpeServiceRate(companyTax.getSpeServiceRate());
				makerStudio.setSpeTaxRate(companyTax.getSpeTaxRate());
				makerStudio.setYearlyHighTaxRate(companyTax.getYearlyHighTaxRate());
				makerStudio.setYearlyHighServiceRate(companyTax.getYearlyHighServiceRate());
				makerStudio.setYearlyHigh2TaxRate(companyTax.getYearlyHigh2TaxRate());
				makerStudio.setYearlyHigh2ServiceRate(companyTax.getYearlyHigh2ServiceRate());
				makerStudio.setYearlyHigh3TaxRate(companyTax.getYearlyHigh3TaxRate());
				makerStudio.setYearlyHigh3ServiceRate(companyTax.getYearlyHigh3ServiceRate());
				makerStudio.setFixedService(companyTax.getFixedService());
				makerStudio.setFixedServiceRate(companyTax.getFixedServiceRate());
			}

			//项目服务费
			boolean isSpecialInvoice = NumberUtil.safeInt(project.getInvoicetype()) == 2;
			ProjectServiceChargeDto serviceCharge = coreProjectService.calcStudioServiceCharge(makerStudio, project.getCompid(), projectid,
					projectType, isSpecialInvoice, dealAmount, CalcAmountType.CHECKED);

			//项目税金
			ProjectTaxFeeDto taxFee = coreProjectService.calcStudioTaxFee(makerStudio, projectid, projectType, isSpecialInvoice, dealAmount,
					CalcAmountType.CHECKED);

			//如果服务费和税金之和大于项目成交价,则直接报错.
			BigDecimal payAmount = project.getProjectdealamount().subtract(serviceCharge.getServiceCharge()).subtract(taxFee.getTaxFee());
			if (payAmount.doubleValue() < 0) {
				throw SmartException.of(StatusMsg.StatusMsg_311);
			}

			//更新金额
			BigDecimal payUserAmount = project.getProjectdealamount().subtract(serviceCharge.getServiceCharge()).subtract(taxFee.getTaxFee());

			project.setProjectPayAmount(payUserAmount)
					.setProjectBaseServiceRate(serviceCharge.getBaseServiceRatio())
					.setProjectservicecharge(serviceCharge.getServiceCharge())
					.setProjectPartnerServiceRate(serviceCharge.getPartnerProjectServiceRatio())
					.setProjectTaxRate(taxFee.getTaxRatio())
					.setProjecttaxfee(taxFee.getTaxFee())
					.updateById();

			ProjectPaymentService projectPaymentService = getProjectPaymentService(project);
			if (projectPaymentService != null) {
				return projectPaymentService.handlePayment(project);
			}
			throw SmartException.of(StatusMsg.StatusMsg_330);
		} finally {
			// 释放分布式锁
			redisService.releaseLock(key);
		}
	}

	@Override
	public ProjectPaymentService getProjectPaymentService(CompanyProject project) {
		Integer payId = project.getPayId();

		if (payId == CompanyPayType.OFFLINE_DIRECT) {
			// 项目款线下支付,直接验收成功
			return offlinePaymentService;
		} else if (payId == CompanyPayType.PLATFORM_OFFLINE) {
			// 平台线下代付
			return jiugeOfflinePaymentService;
		} else {
			// 平台线上支付
			return jiugeUnifyPaymentService;
		}
	}

	@Override
	public SmartResult handleRepayUser(CompanyProject project) {
		ProjectPaymentService projectPaymentService = getProjectPaymentService(project);
		if (projectPaymentService != null) {
			return projectPaymentService.handlePayUser(project);
		}
		throw SmartException.of(StatusMsg.StatusMsg_330);
	}

	@Override
	public SmartResult handleRepayJiuge(CompanyProject project) {
		ProjectPaymentService projectPaymentService = getProjectPaymentService(project);
		if (projectPaymentService != null) {
			return projectPaymentService.handlePayJiugeCharge(project);
		}
		throw SmartException.of(StatusMsg.StatusMsg_330);
	}

	/**
	 * 项目款项在第三方支付公司的代付交易成功后，处理后续的业务,企业订单状态修改，产生创客账户流水。
	 *
	 * @param trade
	 */
	@Override
	public void doAfterPayUserTradeSucceed(TradeRecord trade) {
		if (trade.getProjectid() > 0) {
			//项目完成
			CompanyProject project = new CompanyProject().selectById(trade.getProjectid());
			ProjectPaymentService projectPaymentService = getProjectPaymentService(project);
			if (projectPaymentService != null) {
				projectPaymentService.doAfterPayUserTradeSucceed(project, trade);
			}
		}
	}

	/**
	 * 项目服务费支付给九歌统一账户后,处理后续
	 *
	 * @param trade
	 */
	@Override
	public void doAfterPayJiugeTradeSucceed(TradeRecord trade) {
		if (trade.getProjectid() > 0) {
			//项目完成
			CompanyProject project = new CompanyProject().selectById(trade.getProjectid());
			ProjectPaymentService projectPaymentService = getProjectPaymentService(project);
			if (projectPaymentService != null) {
				projectPaymentService.doAfterPayJiugeTradeSucceed(project, trade);
			}
		}
	}

	@Override
	public void handleOfflineProjectPaidFinish(Invoice invoice) {
		LogUtil.info("处理线下支付服务费成功后的状态: invoiceid = " + invoice.getId());

		CompanyProject project = new CompanyProject().selectById(invoice.getProjectid());
		if (project == null) return;

		handleUserProjectAccountFlow(project, 0);
		coreBrokerageService.handleZhiduoduoProjectPartnerBrokerage(project, 0, "");

		boolean iu = invoice.setOfflinePayState(Constants.OFFLINE_HANDLED).updateById();
		boolean pu = project.setOfflinePayState(Constants.OFFLINE_HANDLED).updateById();
	}

	@Override
	public void handleUserProjectAccountFlow(CompanyProject project, int tradeid) {
		if (project == null) return;

		int projectid = project.getProjectid();
		Integer userid = project.getUserid();

		// 判断是否是合伙人提现发布的项目,是的话, 需要修改状态
		List<Integer> wdids = StringUtil.splitToInt(project.getPartnerWithdrawId(), ",");
		if (CollectionUtils.isNotEmpty(wdids)) {
			for (Integer wdid : wdids) {
				PartnerStudioWithdraw partnerStudioWithdraw = new PartnerStudioWithdraw().selectById(wdid);
				if (partnerStudioWithdraw == null) continue;
				partnerStudioWithdraw.setEndtime(new Date())
						.setProjectid(project.getProjectid())
						.setState(PartnerStudioWithdrawState.COMPLETED)
						.updateById();

				// 合伙人众包项目分佣
				new PartnerBrokerage().setState(PartnerBrokerageState.WITHDRAWED)
						.update(Condition.create().eq("remit_type", RemitType.OFFLINE).eq("wdid", wdid));

				// 合伙人众包成本分佣
				new PartnerMonthlyCrowdCost().setState(PartnerCrowdsourceCostState.WITHDRAWED).update(Condition.create().eq("wdid", wdid));
			}
		}

		//创客项目收入
		boolean projectInsert = new MakerAccountflow().setFlowAmount(project.getProjectdealamount())
				.setFlowname("收到" + project.getProjectname() + "项目款")
				.setFlowtype(1)
				.setAmounttype(0)
				.setProjectid(projectid)
				.setTradeid(tradeid)
				.setUserid(userid)
				.setCompid(project.getCompid())
				.setProjectType(ProjectType.ZHIDUODUO)
				.insert();

		//创客服务费支出
		boolean serviceInsert = new MakerAccountflow().setFlowAmount(project.getProjectservicecharge())
				.setFlowtype(2)
				.setAmounttype(1)
				.setFlowname(project.getProjectname() + "项目服务费")
				.setProjectid(projectid)
				.setTradeid(tradeid)
				.setUserid(userid)
				.setCompid(project.getCompid())
				.setProjectType(ProjectType.ZHIDUODUO)
				.insert();

		//创客个税税费
		if (project.getProjecttaxfee().doubleValue() > 0) {
			new MakerAccountflow().setFlowAmount(project.getProjecttaxfee())
					.setFlowtype(2)
					.setAmounttype(2)
					.setFlowname(project.getProjectname() + "税金")
					.setProjectid(projectid)
					.setTradeid(tradeid)
					.setUserid(userid)
					.setCompid(project.getCompid())
					.setProjectType(ProjectType.ZHIDUODUO)
					.insert();
		}

		//通知创客
		wxMessageService.notifyUserIncomeChecked(projectid);

		//创客首次完成交易，给创客发送问卷调查
		int makerCount = new CompanyProject().selectCount(Condition.create().eq("userid", userid).eq("state", 20));
		if (makerCount == 1) {
			sendMakerSurveyMessage(userid);
			MakerStudio studio = new MakerStudio().selectById(userid);
			//标记第一次完成任务，可以去开税户。
			if (studio.getTaxAcctState() == Constants.STUDIO_TAX_ACCT_NOT_QUALIFIED) {
				studio.setUserid(userid)
						.setTaxAcctState(Constants.STUDIO_TAX_ACCT_QUALIFIED)
						.setOpenTaxAcctStarttime(new Date())
						.updateById();
			}
			//ceo通知首次交易开票
			String studiolicensephoto = studio.getStudiolicensephoto();
			boolean hasPhoto = StringUtil.isNotEmpty(studiolicensephoto);
			ceoNoticeService.recordFirstInvoice(projectid, hasPhoto);
		} else {
			//ceo通知普通项目交易开票
			ceoNoticeService.recordInvoice(projectid);
		}

		//给企业发送问卷调查
		Integer compid = project.getCompid();
		int companyCount = new CompanyProject().selectCount(Condition.create().eq("compid", compid).eq("state", 20));
		if (companyCount == 1) {
			sendCompanySurveyMessage(compid);
		}

		//创客季度超过３０万时给ＣＥＯ推送消息；创客年度超过７５万时给ＣＥＯ推送消息；
		sendMakerAmountNotice(userid);
	}

	private void sendMakerAmountNotice(Integer userid) {
		StudioDetailDto studioDetail = makerStudioMapper.getStudioDetail(userid);
		ProjectDto projectDto = projectMapper.getuserLastProject(0, userid, CompanyProjectState.COMPLETED);

		BigDecimal projectdealamount = projectDto.getProjectdealamount();
		BigDecimal quarterTotalAmount = coreProjectService.getUserQuarterTotalAmount(userid, CalcAmountType.FINISHED)
				.subtract(projectdealamount);
		BigDecimal yearlyTotalAmount = coreProjectService.getUserYearlyTotalAmount(userid, CalcAmountType.FINISHED)
				.subtract(projectdealamount);

		int exceed = coreProjectService.checkTotalAmountJustExceedType(yearlyTotalAmount.doubleValue(), quarterTotalAmount.doubleValue(),
				projectdealamount.doubleValue());
		switch (exceed) {
			case 1:
				String content = "创客季度金额超额提醒" + "\n工作室名：" + studioDetail.getUsername() + "\n姓名：" + studioDetail.getUsername() + "\n当前季度已交易总金额：" +
						quarterTotalAmount.toString();
//				dingdingNoticeService.sendNotice(GroupCode.NORMAL, content);
				//微企通知胡刚和tina
				new Thread(() -> commonService.enterpriseAutomaticFreezing(28,content)).start();
				new Thread(() -> commonService.enterpriseAutomaticFreezing(44,content)).start();
				break;
			case 2:
			case 3:
			case 4:
			case 5:
				String content5 = "创客年度金额超额提醒\n" + "工作室名：" + studioDetail.getUsername() + "\n姓名：" + studioDetail.getUsername() + "\n当前年度已交易总金额：" +
						yearlyTotalAmount.toString();
//				dingdingNoticeService.sendNotice(GroupCode.NORMAL, content);
				//微企通知胡刚和tina
				new Thread(() -> commonService.enterpriseAutomaticFreezing(28,content5)).start();
				new Thread(() -> commonService.enterpriseAutomaticFreezing(44,content5)).start();
				break;
			default:
				break;

		}

	}

	private void sendCompanySurveyMessage(Integer compid) {
		String companyUrl = new SystemCfg().selectById(Constants.KEY_COMPANY_SURVEY_URL).getCfgValue();
		if (StringUtil.isNotEmpty(companyUrl)) {
			String title = new SystemCfg().selectById(Constants.KEY_COMPANY_SURVEY_TITLE).getCfgValue();
			String content = new SystemCfg().selectById(Constants.KEY_COMPANY_SURVEY_CONTENT).getCfgValue();
			Company company = new Company().selectById(compid);
			wxMessageService.sendSurveyNotice(title, content, companyUrl, company.getOpenid());
		}
	}

	private void sendMakerSurveyMessage(Integer userid) {
		String makerUrl = new SystemCfg().selectById(Constants.KEY_MAKER_SURVEY_URL).getCfgValue();
		if (StringUtil.isNotEmpty(makerUrl)) {
			String title = new SystemCfg().selectById(Constants.KEY_MAKER_SURVEY_TITLE).getCfgValue();
			String content = new SystemCfg().selectById(Constants.KEY_MAKER_SURVEY_CONTENT).getCfgValue();
			Maker maker = new Maker().selectById(userid);
			wxMessageService.sendSurveyNotice(title, content, makerUrl, maker.getOpenid());
		}
	}

	public void handleCompanyOrderAfter(CompanyProject project) {

		//企业月度交易超过１００万时给ＣＥＯ推送消息；
		BigDecimal amount = projectMapper.getMonthAmountByCompid(project.getCompid());
		if (amount.doubleValue() > 1000000) {
			Company company = new Company().selectById(project.getCompid());
			String content = "企业月度交易超过100万提醒\n企业名：" + company.getCompname() + "\n当前月度交易金额：" + amount.toString();
//			dingdingNoticeService.sendNotice(GroupCode.NORMAL, content);
			//微企通知胡刚和tina
			new Thread(() -> commonService.enterpriseAutomaticFreezing(28,content)).start();
			new Thread(() -> commonService.enterpriseAutomaticFreezing(44,content)).start();
		}
	}

	@Override
	public ProjectDto getProjectDetail(int projectid) {
		ProjectDto projectDetail = projectMapper.getProjectDetail(projectid);

		//项目剩余天数
		Date now = new Date();
		int projectcycle = projectDetail.getProjectcycle();
		if (projectDetail.getProjectstart() != null) {
			int leftDays = projectcycle - DateUtil.getIntervalDays(projectDetail.getProjectstart(), now);
			projectDetail.setLeftDays(leftDays);
		}

		//项目分类名
		SystemProjectcategory parentCategory = projectCategoryMapper.getParentCategory(projectDetail.getCategoryid());
		if (parentCategory != null) {
			projectDetail.setCategoryname(parentCategory.getProjectcategory());
		}

		//项目支付状态
		TradeRecord tradeRecord = getCompanyPayUserAmountTradeRecord(projectid);
		if (tradeRecord != null) {
			projectDetail.setTradeid(tradeRecord.getTradeid()).setTradestate(tradeRecord.getTradestate()).setRepay(tradeRecord.getRepay());
		}
		//项目发票状态
		Invoice invoice = invoiceMapper.findByProjectid(projectid, ProjectType.ZHIDUODUO);
		if (invoice != null) {
			projectDetail.setInvoiceState(invoice.getState());
		}
		return projectDetail;
	}

	@Override
	public TradeRecord getCompanyPayUserAmountTradeRecord(int projectid) {
		return new TradeRecord().selectOne(Condition.create()
				.eq("projectid", projectid)
				.eq("business_type", Constants.KLT_PAY_BUSINESS_TYPE_USER_AMOUNT)
				.orderBy("tradeid", false)
				.last("limit 1"));
	}

//	@Override
//	public TradeRecord getCompanyPayJiugeChargeTradeRecord(int projectid) {
//		return new TradeRecord().selectOne(Condition.create()
//				.eq("projectid", projectid)
//				.eq("business_type", Constants.KLT_PAY_BUSINESS_TYPE_JIUGE_CHARGE)
//				.orderBy("tradeid", false)
//				.last("limit 1"));
//	}
//
//	@Override
//	public BigDecimal getPayJiugeCharge(CompanyProject project) {
//		//实际给九歌的手续费金额. 减去1.5元,是开联通扣掉的转账手续费. 对公1元,对创客个人0.5元,对创客公户1元
//		//专票项目，使用对公账户，普票项目，使用个人账户
//		float transferServiceCharge = 1;
//		Integer invoicetype = project.getInvoicetype();
//		if (invoicetype == 2) transferServiceCharge += 1;
//		else transferServiceCharge += 0.5;
//
//		return project.getProjectservicecharge().add(project.getProjecttaxfee()).subtract(BigDecimal.valueOf(transferServiceCharge));
//	}
//
//	@Override
//	public BigDecimal getProjectMinimumAmount(CompanyProject project) {
//		if (project == null) return BigDecimal.ZERO;
//
//		Double projectBaseServiceRate = NumberUtil.safeDouble(project.getProjectBaseServiceRate());
//		Double projectPartnerServiceRate = NumberUtil.safeDouble(project.getProjectPartnerServiceRate());
//		Double projectTaxRate = NumberUtil.safeDouble(project.getProjectTaxRate());
//
//		double rate = projectBaseServiceRate + projectPartnerServiceRate + projectTaxRate;
//		BigDecimal payJiugeCharge = getPayJiugeCharge(project);
//		if (rate != 0) {
//			return payJiugeCharge.divide(BigDecimal.valueOf(rate), 2, RoundingMode.CEILING);
//		}
//
//		return project.getProjectamount();
//	}
}
